//! Supervision tree for managing and supervising actors

use std::collections::HashMap;
use std::sync::Arc;
use std::any::Any;

use crate::actor::{PID, ActorError, SupervisorDirective, DefaultActorContext};
use crate::supervision::RestartStatistics;
use parking_lot::RwLock;
use tracing::{info, warn, debug};

/// A supervision tree for managing actor hierarchies
#[derive(Clone)]
pub struct SupervisionTree {
    /// Name of the supervision tree
    name: String,
    
    /// Map of child PIDs to restart statistics
    children: Arc<RwLock<HashMap<PID, RestartStatistics>>>,
    
    /// Supervisor strategy function
    strategy_fn: Arc<dyn Fn(&ActorError) -> SupervisorDirective + Send + Sync>,
}

impl SupervisionTree {
    /// Create a new supervision tree
    pub fn new(
        name: impl Into<String>,
        strategy_fn: impl Fn(&ActorError) -> SupervisorDirective + Send + Sync + 'static
    ) -> Self {
        Self {
            name: name.into(),
            children: Arc::new(RwLock::new(HashMap::new())),
            strategy_fn: Arc::new(strategy_fn),
        }
    }
    
    /// Add a child to the supervision tree
    pub fn add_child(&self, pid: PID) {
        debug!("Adding child {} to supervision tree {}", pid, self.name);
        self.children.write().insert(pid, RestartStatistics::new());
    }
    
    /// Remove a child from the supervision tree
    pub fn remove_child(&self, pid: &PID) {
        debug!("Removing child {} from supervision tree {}", pid, self.name);
        self.children.write().remove(pid);
    }
    
    /// Get all child PIDs
    pub fn children(&self) -> Vec<PID> {
        self.children.read().keys().cloned().collect()
    }
    
    /// Handle a child failure
    pub fn handle_failure(
        &self,
        ctx: &mut DefaultActorContext,
        pid: &PID,
        reason: &ActorError,
        message: Option<Box<dyn Any + Send>>,
    ) -> bool {
        // Log the failure
        warn!("Child actor {} failed in tree {}: {}", pid, self.name, reason);
        
        // Update restart statistics
        if let Some(stats) = self.children.write().get_mut(pid) {
            stats.record_failure();
        }
        
        // Apply the supervisor strategy
        let directive = (self.strategy_fn)(reason);
        
        match directive {
            SupervisorDirective::Resume => {
                info!("Resuming actor {}", pid);
                true
            }
            SupervisorDirective::Restart => {
                info!("Restarting actor {}", pid);
                // In a real implementation, this would handle restarting the actor
                true
            }
            SupervisorDirective::Stop => {
                info!("Stopping actor {}", pid);
                self.remove_child(pid);
                false
            }
            SupervisorDirective::Escalate => {
                info!("Escalating failure of actor {} to parent", pid);
                self.remove_child(pid);
                false
            }
        }
    }
} 